/* 
  Copyright (c) SilverLining 2015
  Date:    2016-1-7
  File:    object.cpp  
  Description: 

*/

#include "stdafx.h"

using namespace m::alloc;

namespace m
{
	object::object()
		: _Weak(nullptr),
		RefCount(1),
		_Id(ID_NOTARCHIVED),
		_Archiver(nullptr)
	{
	}
	
	object::~object()
	{
		// Deleting during archival is a potential memory leak.
		assert(!_Archiver);
	}
	
	void object::reference() volatile
	{
		DBGREFERENCE(this, 1);
		size_t ct = InterlockedIncrement(&RefCount);
		assert(ct > 1);
	}
	
	void object::reference(const size_t & additionalRefCount) volatile
	{
		if (additionalRefCount > 0)
		{
			DBGREFERENCE(this, additionalRefCount);
#if _WIN64 || _amd64_
			size_t ct = InterlockedAdd64((volatile LONGLONG*)&RefCount, static_cast<LONGLONG>(additionalRefCount));
#else
			size_t ct = InterlockedAdd((volatile LONG*)&RefCount, static_cast<LONG>(additionalRefCount));
#endif
			assert(ct > 1);
		}
	}
	
	weak_ref* object::reference_weak() volatile
	{
		// In order to atomically create this object, we need to synchronize with
		// other threads which could potentially be creating it at the same time.
		// If we're the thread that moves it from its null to not null state,
		// we keep ours and initialize it. Otherwise, we release ours.
		while (_Weak == nullptr)
		{
			weak_ref* newWeak = new weak_ref(this);
			if (InterlockedCompareExchangePointer((volatile PVOID*)&_Weak, newWeak, nullptr) != nullptr)
			{
				newWeak->release();
			}
		}

		// We or another thread atomically created it. Now, reference it and return it.
		DBGREFERENCEWEAK((void*)this);
		_Weak->reference();
		return const_cast<weak_ref*>(static_cast<volatile weak_ref*>(_Weak));
	}
	
	void object::release() volatile
	{
		assert(RefCount > 0);
		if (RefCount > 0)
		{
			DBGRELEASE((void*)this, 1);
			if (InterlockedDecrement(&RefCount) == 0)
			{
				if (_Weak != nullptr)
				{
					static_cast<volatile weak_ref*>(_Weak)->_Value = nullptr;
					_Weak->release();
				}
				delete this;
				return;
			}
		}
	}
	
	std::wstring object::to_string() const
	{
		std::string str = typeid(this).name();
		std::wstring ret;
		ret.assign(str.begin(), str.end());
		return ret;	
	}

	void * object::operator new(size_t sz)
	{
		void* ret = ::operator new(sz, aligned);
		object* thisObj = (object*)ret;
		thisObj->_Pool = nullptr;
		return ret;
	}
		
	void object::operator delete(void * ptr)
	{
		object* thisObj = (object*)ptr;
		if (thisObj->_Pool)
		{
			thisObj->_Pool->put(ptr);
			return;
		}
		::operator delete(ptr, aligned);
	}

	void object::read(archiver * archiver)
	{
	}

	void object::write(archiver * archiver)
	{
	}
} // m